from datetime import datetime, time, timedelta
from odoo import fields
from odoo.exceptions import UserError

VALIDITY_SELECTION = [('day', '天'), ('week', '周'), ('month', '月'), ('year', '年')]
TIME_OPTION = [('according_rule', '默认'), ('custom', '自定义')]


class MarketingCouponFunc(object):
    """
    Model:
        满足所有营销优惠券涉及的算法逻辑

    Param:
        -env:odoo env
    """

    def __init__(self, env):
        self.env = env

    def get_discounted_price(self, record, price):
        """
        Params:
        -record:记录
        -price:优惠前价格
        Return:
        -discounted_price:优惠后价格
        """
        # 若为全免券，减到0
        if record.coupon_type == 'free_charge':
            return 0.0
        if record.coupon_type == 'spend_save':
            return price - record.par_value
        if record.coupon_type == 'Discount':
            return price * (1 - record.discount_value)

    def calculate_time(self, selection, start_date, validity):
        """计算优惠券有效期"""
        end_date = None
        if selection == 'day':
            end_date = start_date + timedelta(days=validity)
        if selection == 'week':
            end_date = start_date + timedelta(weeks=validity)
        if selection == 'month':
            end_date = start_date + timedelta(days=30 * validity)
        if selection == 'year':
            end_date = start_date + timedelta(days=365 * validity)
        return end_date

    def backdoor_get_available_coupon(self, customer_id, rp_ship_order_value_added_line_ids, shipper_mail_route_id, all_adjust_marketing_price):
        """
        获取客户可用的优惠券列表
        Param:
        -customer_id:客户记录
        -rp_ship_order_value_added_line_ids:用户获取的增值服务集合
        -shipper_mail_route_id:托运商邮路id
        -all_adjust_marketing_price:调价后总金额
        """
        available_sva = self.env['rp.available.customer.coupon.tran'].browse()
        # 获取客户所有的可用优惠券
        time_now = datetime.today().date()
        # 添加筛选（达到门槛,未过期,未使用）
        customer_all_coupons = customer_id.rp_customer_coupon_ids.filtered(lambda r: all([r.coupon_threshold <= all_adjust_marketing_price,
                                                                                          r.customer_coupon_start_date <= time_now, r.customer_coupon_expired_date >= time_now,
                                                                                          r.rp_coupon_status == 'not_use']))
        # 处理单一增值服务（一类和二类均包含）
        coupons_for_value_add = customer_all_coupons.filtered(lambda r: r.coupon_for == 'single_value_add')
        for record in rp_ship_order_value_added_line_ids:
            available_coupon_for_value_add = coupons_for_value_add.filtered(lambda r: r.rp_coupon_valued_added_id.shipper_value_added_id.id == record.value_added_id.id)
            if len(available_coupon_for_value_add) != 0:
                # 可能客户手里有多个优惠券可以对同一个增值服务进行优惠
                for coupon_item in available_coupon_for_value_add:
                    dict_data = {
                        'name': coupon_item.name,
                        'code': coupon_item.code,
                        'par_value': coupon_item.par_value,
                        'coupon_type': coupon_item.coupon_type,
                        'rp_coupon_valued_added_id': coupon_item.rp_coupon_valued_added_id.id,
                        'discount_value': coupon_item.discount_value,
                        'rp_customer_coupon_id': coupon_item.id,
                        'coupon_for': coupon_item.coupon_for,
                        'is_stacked': coupon_item.is_stacked
                    }
                    sva_tran = self.env['rp.available.customer.coupon.tran'].create([dict_data])
                    available_sva = available_sva | sva_tran

        # 处理所有增值服务（只有二类）
        # 判断增值服务明细中是否存在二类的增值服务
        selected_value_added_two = rp_ship_order_value_added_line_ids.filtered(lambda r: r.value_added_category == 'two')
        if len(selected_value_added_two) > 0:
            coupons_for_all_value_add = customer_all_coupons.filtered(lambda r: r.coupon_for == 'all_value_add')
            for coupon_record in coupons_for_all_value_add:
                dict_data = {
                    'name': coupon_record.name,
                    'code': coupon_record.code,
                    'par_value': coupon_record.par_value,
                    'discount_value': coupon_record.discount_value,
                    'rp_customer_coupon_id': coupon_record.id,
                    'coupon_type': coupon_record.coupon_type,
                    'coupon_for': coupon_record.coupon_for,
                    'rp_coupon_valued_added_id': coupon_record.rp_coupon_valued_added_id,
                    'is_stacked': coupon_record.is_stacked
                }
                sva_tran = self.env['rp.available.customer.coupon.tran'].create([dict_data])
                available_sva = available_sva | sva_tran

        # 处理单一邮路
        coupon_for_single_mail_route = customer_all_coupons.filtered(lambda r: r.coupon_for == 'single_mail_route' and r.rp_coupon_mail_route_id.id == shipper_mail_route_id.id)
        for coupon_record in coupon_for_single_mail_route:
            dict_data = {
                'name': coupon_record.name,
                'code': coupon_record.code,
                'par_value': coupon_record.par_value,
                'discount_value': coupon_record.discount_value,
                'rp_customer_coupon_id': coupon_record.id,
                'coupon_type': coupon_record.coupon_type,
                'coupon_for': coupon_record.coupon_for,
                'rp_coupon_valued_added_id': coupon_record.rp_coupon_valued_added_id,
                'is_stacked': coupon_record.is_stacked
            }
            sva_tran = self.env['rp.available.customer.coupon.tran'].create([dict_data])
            available_sva = available_sva | sva_tran

        # 处理所有邮路
        coupons_for_operation = customer_all_coupons.filtered((lambda r: r.coupon_for == 'all_mail_route'))
        for coupon_record in coupons_for_operation:
            dict_data = {
                'name': coupon_record.name,
                'code': coupon_record.code,
                'par_value': coupon_record.par_value,
                'discount_value': coupon_record.discount_value,
                'rp_customer_coupon_id': coupon_record.id,
                'coupon_type': coupon_record.coupon_type,
                'coupon_for': coupon_record.coupon_for,
                'rp_coupon_valued_added_id': coupon_record.rp_coupon_valued_added_id,
                'is_stacked': coupon_record.is_stacked
            }
            sva_tran = self.env['rp.available.customer.coupon.tran'].create([dict_data])
            available_sva = available_sva | sva_tran
        return available_sva

    def backdoor_get_discounted_total_price(self, rp_shipper_order_coupon_line_ids, rp_ship_order_value_added_line_ids, mail_route_marketing_adjust_result, shipper_mail_route_id):
        """
        获取优惠后各分类(邮路，头尾程，增值服务）总价格
        Param:
        -rp_shipper_order_coupon_line_ids:已选优惠券明细
        -rp_ship_order_value_added_line_ids:已选增值服务明细
        -mail_route_marketing_adjust_result:邮路调后价（被动调后价）
        -shipper_mail_route_id:托运商邮路
        Return:
        -dict:价格字典
        Description:
        -进入此函数优惠券类型：
             situation1-同一条件下全免（只有一项）
             situation2-同一条件下若干可叠加（满减券或折扣券）
             situation3-同一条件下的（满减券+折扣券）
        """

        # 处理邮路（全部邮路和单一邮路）
        available_coupon_for_mail_route_ids = rp_shipper_order_coupon_line_ids.filtered(lambda r: any([r.coupon_for == 'all_mail_route', r.coupon_for == 'single_mail_route' and r.rp_coupon_mail_route_id.id == shipper_mail_route_id.id]))
        sum_for_mail_route = mail_route_marketing_adjust_result
        free_charge_ids = available_coupon_for_mail_route_ids.filtered(lambda r: r.coupon_type == 'free_charge')
        if len(free_charge_ids) > 0:
            # 所有邮路全免和单一邮路全免同时出现只走一次，全部为所有邮路全免或所有是单一邮路全免不会进入此方法
            # 先执行全免券,全免券执行后其他同类型的优惠券失效
            sum_for_mail_route = self.get_discounted_price(free_charge_ids[0], sum_for_mail_route)
        else:
            # 执行满减券
            spend_save_values = available_coupon_for_mail_route_ids.filtered(lambda r: r.coupon_for == 'spend_save').mapped(lambda r: r.par_value)
            total_save_values = sum(spend_save_values)
            sum_for_mail_route = sum_for_mail_route - total_save_values if (sum_for_mail_route - total_save_values) >= 0 else 0
            if sum_for_mail_route > 0:
                discount_values = available_coupon_for_mail_route_ids.filtered(lambda r: r.coupon_type == 'Discount').mapped(lambda r: r.discount_value)
                total_discount = sum(discount_values) if sum(discount_values) <= 1 else 1
                sum_for_mail_route = sum_for_mail_route * (1 - total_discount)

        # 处理单一增值服务（二类）和全部增值服务
        sum_for_value_add = 0.0
        # 筛选出同一托运商模板下的增值服务
        available_coupon_for_value_add_two = rp_shipper_order_coupon_line_ids.filtered(lambda r: any([r.coupon_for == 'single_value_add' and r.rp_coupon_valued_added_id.shipper_value_added_category == 'two' and r.rp_coupon_valued_added_id.shipper_id.id == shipper_mail_route_id.shipper_id.id, r.coupon_for == 'all_value_add']))
        value_added_two = rp_ship_order_value_added_line_ids.filtered(lambda r: r.value_added_category == 'two')  # 二类的增值服务
        for record in value_added_two:
            available_coupon = available_coupon_for_value_add_two.filtered(lambda r: r.rp_coupon_valued_added_id.id == record.value_added_id.id)
            free_charge_coupons = available_coupon.filtered(lambda r: r.coupon_type == 'free_charge' and r.rp_coupon_valued_added_id.id == record.value_added_id.id)
            if len(free_charge_coupons) > 0:
                # 处理全免券
                discount_price = self.get_discounted_price(free_charge_coupons[0], record.adjusted_price_for_marketing)
            else:
                # 处理满减券
                spend_save_values = available_coupon.filtered(lambda r: r.coupon_type == 'spend_save').mapped(lambda r: r.par_value)
                total_save_values = sum(spend_save_values)
                discount_price = record.adjusted_price_for_marketing - total_save_values if (record.adjusted_price_for_marketing - total_save_values) >= 0 else 0
                if discount_price > 0:
                    # 计算折扣值
                    discount_values = available_coupon.filtered(lambda r: r.coupon_for == 'Discount').mapped(lambda r: r.discount_value)
                    total_discount_values = sum(discount_values) if sum(discount_values) <= 1 else 1
                    discount_price = discount_price * (1 - total_discount_values)
            record.write({'discounted_price_for_marketing': discount_price, 'used_coupon_ids': [(6, 0, available_coupon.mapped('rp_customer_coupon_id').ids)]})
            sum_for_value_add += discount_price
        # 处理增值服务（一类）
        sum_for_operation = 0.0
        available_coupon_for_value_add_one = rp_shipper_order_coupon_line_ids.filtered(lambda r: r.coupon_for == 'single_value_add' and r.rp_coupon_valued_added_id.shipper_value_added_category == 'one' and r.rp_coupon_valued_added_id.shipper_id.id == shipper_mail_route_id.shipper_id.id)
        value_added_one = rp_ship_order_value_added_line_ids.filtered(lambda r: r.value_added_category == 'one')  # 一类的增值服务
        for record in value_added_one:
            available_coupon = available_coupon_for_value_add_one.filtered(lambda r: r.rp_coupon_valued_added_id.id == record.value_added_id.id)  # 单独适用于本增值的一类单邮路优惠券
            free_charge_coupons = available_coupon.filtered(lambda r: r.coupon_type == 'free_charge')
            if len(free_charge_coupons) > 0:
                discount_price = self.get_discounted_price(free_charge_coupons[0], record.adjusted_price_for_marketing)
            else:
                # 处理全免券
                spend_save_values = available_coupon.filtered(lambda r: r.coupon_type == 'spend_save').mapped(lambda r: r.par_value)
                sum_spend_save_values = sum(spend_save_values)
                discount_price = record.adjusted_price_for_marketing - sum_spend_save_values if (record.adjusted_price_for_marketing - sum_spend_save_values) >= 0 else 0
                if discount_price > 0:
                    discount_values = available_coupon.filtered(lambda r: r.coupon_for == 'Discount').mapped(lambda r: r.discount_value)
                    sum_discount_values = sum(discount_values) if sum(discount_values) <= 1 else 1
                    discount_price = record.adjusted_price_for_marketing * (1 - sum_discount_values)
            record.write({'discounted_price_for_marketing': discount_price, 'used_coupon_ids': [(6, 0, available_coupon.mapped('rp_customer_coupon_id').ids)]})
            sum_for_operation += discount_price

        return {
            'mail_discount_price': sum_for_mail_route if sum_for_mail_route >= 0 else 0.0,
            'value_add_discount_price': sum_for_value_add if sum_for_value_add >= 0 else 0.0,
            'used_coupon_ids_for_mail': available_coupon_for_mail_route_ids.mapped('rp_customer_coupon_id').ids,
            'sum_for_operation': sum_for_operation
        }

    def validate_coupon_info(self, template_id):
        """
            校验优惠券模板是否过期
            Param:
            -template_id:优惠券模板ID
        """
        # 基本信息
        start_date_option = template_id.start_date_option  # 开始选项
        end_date_option = template_id.end_date_option  # 结束选项
        end_date = template_id.end_date  # 结束时间
        # 【开始时间为默认，结束时间为自定义|开始时间为自定义，结束时间为自定义|开始时间为自定义，结束时间为默认】---只有这三种情况可能出现问题
        if end_date and not all([(start_date_option == TIME_OPTION[0][0], end_date_option == TIME_OPTION[0][0])]):
            if fields.Date.today() > end_date:
                raise UserError('选择的优惠券模板已过期！')

    def issue_coupon_to_customer(self, rp_marketing_coupon_template_id, rp_customer_id):
        """
        发放优惠券
        Param:
        -rp_marketing_coupon_template_id:优惠券模板ID
        -rp_customer_id:发送优惠券的目标方
         Return:
        -coupon_id:优惠券ID
        """
        # 优惠券校验
        self.validate_coupon_info(rp_marketing_coupon_template_id)
        if rp_marketing_coupon_template_id:
            # 基本信息
            selection = rp_marketing_coupon_template_id.rp_coupon_validity_selection
            validity = rp_marketing_coupon_template_id.rp_coupon_validity
            start_date = rp_marketing_coupon_template_id.start_date
            end_date = rp_marketing_coupon_template_id.end_date
            time_now = fields.date.today()
            # 处理信息
            if rp_marketing_coupon_template_id.start_date_option == 'according_rule':
                if rp_marketing_coupon_template_id.end_date_option == 'custom':
                    selection = VALIDITY_SELECTION[0][0]
                    start_date = time_now
                    validity = (rp_marketing_coupon_template_id.end_date - start_date).days
                if rp_marketing_coupon_template_id.end_date_option == 'according_rule':
                    start_date = time_now
                    end_date = MarketingCouponFunc(self.env).calculate_time(selection, start_date, validity)
            if rp_marketing_coupon_template_id.start_date_option == 'custom' and rp_marketing_coupon_template_id.end_date_option == 'custom':
                start_date = time_now
                end_date = MarketingCouponFunc(self.env).calculate_time(selection, start_date, validity)
                validity = (rp_marketing_coupon_template_id.end_date - start_date).days

            # 处理优惠券状态
            coupon_state = 'not_active' if start_date > time_now else 'not_use'
            # 优惠券发放
            coupon_data = {
                'rp_customer_id': rp_customer_id.id,
                'name': rp_marketing_coupon_template_id.name,
                'coupon_type': rp_marketing_coupon_template_id.coupon_type,
                'par_value': rp_marketing_coupon_template_id.par_value,
                'discount_value': rp_marketing_coupon_template_id.discount_value,
                'coupon_threshold': rp_marketing_coupon_template_id.coupon_threshold,
                'is_stacked': rp_marketing_coupon_template_id.is_stacked,
                'rp_coupon_validity_selection': selection,
                'rp_coupon_validity': validity,
                'customer_coupon_start_date': start_date,
                'customer_coupon_expired_date': end_date,
                'rp_coupon_status': coupon_state,
                'coupon_for': rp_marketing_coupon_template_id.coupon_for,
                'rp_coupon_template_id': rp_marketing_coupon_template_id.id,
                'rp_coupon_mail_route_id': rp_marketing_coupon_template_id.rp_coupon_mail_route_id.id,
                'rp_coupon_valued_added_id': rp_marketing_coupon_template_id.rp_coupon_valued_added_id.id
            }
            coupon_id = self.env['rp.customer.coupon'].create([coupon_data])
            rp_marketing_coupon_template_id.write({'acquire_count': rp_marketing_coupon_template_id.acquire_count + 1})
            return coupon_id
